package net.gdface.facelog;

import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.gdface.utils.InterfaceDecorator;
import static com.google.common.base.Preconditions.*;

/**
 * {@link IFaceLog}接口实例代理<br>
 * 实现{@link IFaceLog}接口调用时对接口调用过程的状态侦听
 * @author guyadong
 *
 */
public class FacelogDecorator extends InterfaceDecorator<IFaceLog, IFaceLog> {
	private FacelogDecorator(IFaceLog delegate) {
		super(IFaceLog.class,delegate);
		registerListener(new ErrorProbe());
		registerListener(new TokenProbe());
	}

	public FacelogDecorator registerClientAddressProbe(BaseClientAddressProbe listener){
    	checkArgument(registerListener(listener),"FAILT TO register client address probe");
    	return this;
    }
    /**
     * 将{@link IFaceLog}实例封装为接口代理实例返回
     * @param instance
     * @return facelog接口代理实例
     */
    public static FacelogDecorator wrap(IFaceLog instance){
    	return new FacelogDecorator(instance);
    }
	private class TokenProbe extends DefaultProbe{

		@Override
		public void beforeInvoke(Object proxy, Method method, Object[] args) {
			// 服务方法调用开始前初始化上下文对象 TokenContext 
			TokenContext.getCurrentTokenContext().setMethodName(method.getName());
			if(args != null && args.length > 0){
				// 捕获最后一个类型为Token的参数存入TLS
				Object last = args[args.length-1];
				if( last instanceof Token){
					TokenContext.getCurrentTokenContext().setToken(((Token)last));
				}
			}
		}

		@Override
		public void onDone(Object proxy, Method method, Object[] args) {
			// 服务方法结束,清除上下文对象
			TokenContext.getCurrentTokenContext().contextDone();
		}
		
	}
	/**
	 * 调用异常侦听器基类
	 * @author guyadong
	 *
	 */
	private static class ErrorProbe extends DefaultProbe {
	    protected static final Logger logger = LoggerFactory.getLogger(ErrorProbe.class);

		private ErrorProbe() {
		}

		@Override
		public void onError(Object proxy, Method method, Object[] args, Throwable error) {

			if(error instanceof ServiceSecurityException){
				ServiceSecurityException securityException = (ServiceSecurityException)error;
				switch(securityException.getType()){
				case TABLE_INSERT_DENIED:
				case TABLE_UPDATE_DENIED:
				case TABLE_DELETE_DENIED:
					logger.error("PORT:{} FROM:{} BY:{}: MESSAGE:{}",
							method.getName(),
							TokenContext.getCurrentTokenContext().getClientAddress(),
							TokenContext.getCurrentTokenContext().getToken().owner(),
							error.getMessage());
					break;
				default:
					break;
				}
			}	
		}	
	}

	/**
	 * 客户端地址侦听器基类,用于获取当前调用的客户端地址
	 * @author guyadong
	 *
	 */
	public static abstract class BaseClientAddressProbe extends DefaultProbe{

		protected BaseClientAddressProbe() {
		}
		@Override
		public final void beforeInvoke(Object proxy, Method method, Object[] args) {
			// 服务方法调用开始前初始化上下文对象 TokenContext,保存客户端地址到当前上下文
			TokenContext.getCurrentTokenContext().setClientAddress(getClientAddress());
		}
		/**
		 * 返回当前调用的客户端地址
		 * @return 当前调用的客户端地址
		 */
		protected abstract String getClientAddress();
	}
}
